﻿//========================================================= 
/**@file rapidjson_extractor.h
 * @brief RapidJson适配
 * 
 * @date 2018-06-05   19:39:55
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_RAPIDJSON_EXTRACTOR_H_
#define _LIBZHOUYB_RAPIDJSON_EXTRACTOR_H_
//--------------------------------------------------------- 
#include "../../include/Base.h"

#define RAPIDJSON_HAS_STDSTRING 1

#include <rapidjson/rapidjson.h>
#include <rapidjson/document.h>
#include <rapidjson/writer.h>
#include <rapidjson/filereadstream.h>
#include <rapidjson/filewritestream.h>
//--------------------------------------------------------- 
namespace zhou_yb {
namespace wrapper {
namespace rapidjson_extractor {
//--------------------------------------------------------- 
/**
 * @brief * @brief 获取Json数据的辅助类
 * @date 2019-02-22 17:11
 */
class RapidJsonWrapper
{
protected:
    rapidjson::Value* _pValue;
public:
    RapidJsonWrapper() : _pValue(NULL) {}
    RapidJsonWrapper(rapidjson::Value& v) : _pValue(&v) {}

    inline bool IsEmpty() const
    {
        return _pValue == NULL || _pValue->IsNull();
    }
    inline const rapidjson::Value& Value() const
    {
        return *_pValue;
    }

    RapidJsonWrapper operator[](const char* key) const
    {
        if(IsEmpty() || !_pValue->HasMember(key))
            return RapidJsonWrapper();
        return RapidJsonWrapper((*_pValue)[key]);
    }
    RapidJsonWrapper operator[](size_t index) const
    {
        if(IsEmpty() || !_pValue->IsArray())
            return RapidJsonWrapper();
        return RapidJsonWrapper((*_pValue)[index]);
    }

    template<class T>
    T To(const T& defaultVal = T()) const
    {
        // 空的值或无效值
        if(IsEmpty() || !_pValue->Is<T>())
            return defaultVal;
        return _pValue->Get<T>();
    }

    template<class T>
    T ToNumber(const T& defaultVal = T()) const
    {
        if(IsEmpty())
            return defaultVal;
        if(_pValue->IsNumber())
            return _pValue->Get<T>();
        if(_pValue->IsString())
            return ArgConvert::FromString<T>(_pValue->Get<string>());
        return defaultVal;
    }

    template<class T>
    bool Get(T& val) const
    {
        if(IsEmpty() || !_pValue->Is<T>())
            return false;
        val = _pValue->Get<T>();
        return true;
    }
};
//--------------------------------------------------------- 
/**
 * @brief RapidJson辅助接口
 * @date 2018-06-05 22:52:54
 */
class RapidJsonHelper
{
protected:
    //----------------------------------------------------- 
    RapidJsonHelper() {}
    //----------------------------------------------------- 
public:
    /**
     * @brief 将Json值转为字符串
     * @date 2018-06-05 22:53:08
     */
    static string ToString(const rapidjson::Value& val)
    {
        if(val.IsString())
        {
            return val.GetString();
        }
        else if(val.IsBool())
        {
            return ArgConvert::ToString(val.GetBool());
        }
        else if(val.IsDouble())
        {
            return ArgConvert::ToString(val.GetDouble());
        }
        else if(val.IsInt())
        {
            return ArgConvert::ToString(val.GetInt());
        }
        else if(val.IsUint())
        {
            return ArgConvert::ToString(val.GetUint());
        }
        else if(val.IsInt64())
        {
            return ArgConvert::ToString(val.GetInt64());
        }
        else if(val.IsUint64())
        {
            return ArgConvert::ToString(val.GetUint64());
        }
        else if(val.IsFloat())
        {
            return ArgConvert::ToString(val.GetFloat());
        }
        else if(val.IsNull())
        {
            return "";
        }
        else if(val.IsObject())
        {
            rapidjson::StringBuffer buffer;
            rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
            val.Accept(writer);
            return buffer.GetString();
        }
        return val.GetString();
    }
    /**
     * @brief 将Json数组转为IStringArguments中
     * @date 2018-06-05 22:53:33
     */
    static size_t ArrayToARG(const rapidjson::Value& arr, const string& sKey, IStringArguments& arg)
    {
        rapidjson::Value::ConstValueIterator itr = arr.Begin();
        while(itr != arr.End())
        {
            arg.Put(sKey, ToString(*itr));
            ++itr;
        }
        return arr.Size();
    }
    //----------------------------------------------------- 
    /**
     * @brief 尝试将Json值转为对应的类型
     * @date 2018-06-05 22:53:49
     */
    template<class T>
    static bool TryConvert(const rapidjson::Value& json, T& val)
    {
        if(!json.Is<T>())
            return false;
        val = json.Get<T>();
        return true;
    }
    /**
     * @brief 将Json值转为对应的类型,失败时返回提供的值
     * @date 2018-06-05 22:59:42
     */
    template<class T>
    static T Convert(const rapidjson::Value& json, const T& defaultVal)
    {
        T val;
        if(TryConvert(json, val))
            return val;
        return defaultVal;
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
/**
 * @brief 适配RapidJson支持IStringArgParser接口
 * @date 2018-06-05 22:45:24
 */
class RapidJsonArgParser : public IStringArgParser, public RefObject
{
public:
    RapidJsonArgParser() {}
    /// 解析Json
    virtual size_t Parse(const ByteArray& str, IStringArguments& arg)
    {
        // 数据为空时不解析,否则rapidjson会抛异常
        if(str.IsEmpty()) return 0;

        rapidjson::Document doc;
        doc.Parse(str.GetString(), str.GetLength());

        size_t count = 0;
        if(doc.IsArray())
        {
            count += RapidJsonHelper::ArrayToARG(doc, "", arg);
        }
        else if(doc.IsObject())
        {
            rapidjson::Value::ConstMemberIterator itr = doc.MemberBegin();
            while(itr != doc.MemberEnd())
            {
                string name = RapidJsonHelper::ToString(itr->name);
                if(itr->value.IsArray())
                {
                    count += RapidJsonHelper::ArrayToARG(itr->value, name, arg);
                }
                else
                {
                    arg.Put(name, RapidJsonHelper::ToString(itr->value));
                    ++count;
                }
                ++itr;
            }
        }
        return count;
    }
    /// 将KV转为Json字符串
    virtual size_t ToString(const IStringArguments& arg, ByteBuilder& str)
    {
        rapidjson::Document doc;
        rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
        doc.SetObject();

        rapidjson::Value& root = doc;
        IStringArguments::EnumeratorType enumer = arg.GetEnumerator();
        size_t count = 0;
        while(enumer.MoveNext())
        {
            string& sKey = enumer.Current().Key;
            string& sVal = enumer.Current().Value;
            rapidjson::Value::MemberIterator itr = root.FindMember(sKey.c_str());
            rapidjson::Value key(sKey.c_str(), sKey.length());
            rapidjson::GenericStringRef<char> refVal = rapidjson::StringRef(sVal.c_str(), sVal.length());
            if(itr != root.MemberEnd())
            {
                if(itr->value.IsArray())
                {
                    itr->value.PushBack(refVal, allocator);
                    continue;
                }
                rapidjson::Value& val = itr->value;
                rapidjson::Value arr;
                arr.SetArray();
                arr.PushBack(val, allocator);
                arr.PushBack(refVal, allocator);

                root.EraseMember(itr);
                root.AddMember(key, arr, allocator);
            }
            else
            {
                root.AddMember(key, refVal, allocator);
            }
            ++count;
        }
        if(count < 1)
            return 0;

        rapidjson::StringBuffer buffer;
        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
        doc.Accept(writer);

        size_t len = buffer.GetLength();
        str.Append(ByteArray(buffer.GetString(), len));
        return len;
    }
};
//--------------------------------------------------------- 
} // namespace rapidjson_extractor
} // namespace wrapper
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_RAPIDJSON_EXTRACTOR_H_
//========================================================= 